{
 "cells": [
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**问题：**\n",
    "假设你正在为一个电影推荐系统设计一个简单的KNN算法。我们有以下一些用户的电影评分数据，数据由两个特征组成：用户对电影A和电影B的评分，分别在1-5之间。用户的标签（电影类型偏好）是动作片（标签0）或者是喜剧片（标签1）。我们有一个新用户，他给电影A评分为3，电影B评分为4。请问这个用户可能偏好哪种类型的电影？\n",
    "\n",
    "**数据：**\n",
    "\n",
    "| 用户   | 电影A评分 | 电影B评分 | 偏好类型 |\n",
    "| ------ | --------- | --------- | -------- |\n",
    "| 用户1  | 5         | 1         | 动作片   |\n",
    "| 用户2  | 4         | 2         | 动作片   |\n",
    "| 用户3  | 2         | 5         | 喜剧片   |\n",
    "| 用户4  | 1         | 4         | 喜剧片   |\n",
    "| 用户5  | 3         | 2         | 动作片   |\n",
    "| 用户6  | 2         | 5         | 喜剧片   |\n",
    "\n",
    "你需要做以下步骤：\n",
    "1. 构造数据\n",
    "2. 创建KNN模型\n",
    "3. 使用数据训练模型\n",
    "4. 预测新用户的喜好"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 0. 引入核心包"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "from sklearn.neighbors import KNeighborsClassifier"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 1. X, y"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "X = np.array([\n",
    "    [5, 1],   # 用户1（动作片）\n",
    "    [4, 2],   # 用户2（动作片）\n",
    "    [2, 5],   # 用户3（喜剧片）\n",
    "    [1, 4],   # 用户4（喜剧片）\n",
    "    [3, 2],   # 用户5（动作片）\n",
    "    [2, 5]    # 用户6（喜剧片）\n",
    "])\n",
    "y =  np.array([0, 0, 1, 1, 0, 1])   # 0表示动作片，1表示喜剧片"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 2. 创建 KNN 模型\n",
    "k = 1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "knn =  KNeighborsClassifier(n_neighbors=1)"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 3. 训练模型"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<style>#sk-container-id-1 {\n",
       "  /* Definition of color scheme common for light and dark mode */\n",
       "  --sklearn-color-text: #000;\n",
       "  --sklearn-color-text-muted: #666;\n",
       "  --sklearn-color-line: gray;\n",
       "  /* Definition of color scheme for unfitted estimators */\n",
       "  --sklearn-color-unfitted-level-0: #fff5e6;\n",
       "  --sklearn-color-unfitted-level-1: #f6e4d2;\n",
       "  --sklearn-color-unfitted-level-2: #ffe0b3;\n",
       "  --sklearn-color-unfitted-level-3: chocolate;\n",
       "  /* Definition of color scheme for fitted estimators */\n",
       "  --sklearn-color-fitted-level-0: #f0f8ff;\n",
       "  --sklearn-color-fitted-level-1: #d4ebff;\n",
       "  --sklearn-color-fitted-level-2: #b3dbfd;\n",
       "  --sklearn-color-fitted-level-3: cornflowerblue;\n",
       "\n",
       "  /* Specific color for light theme */\n",
       "  --sklearn-color-text-on-default-background: var(--sg-text-color, var(--theme-code-foreground, var(--jp-content-font-color1, black)));\n",
       "  --sklearn-color-background: var(--sg-background-color, var(--theme-background, var(--jp-layout-color0, white)));\n",
       "  --sklearn-color-border-box: var(--sg-text-color, var(--theme-code-foreground, var(--jp-content-font-color1, black)));\n",
       "  --sklearn-color-icon: #696969;\n",
       "\n",
       "  @media (prefers-color-scheme: dark) {\n",
       "    /* Redefinition of color scheme for dark theme */\n",
       "    --sklearn-color-text-on-default-background: var(--sg-text-color, var(--theme-code-foreground, var(--jp-content-font-color1, white)));\n",
       "    --sklearn-color-background: var(--sg-background-color, var(--theme-background, var(--jp-layout-color0, #111)));\n",
       "    --sklearn-color-border-box: var(--sg-text-color, var(--theme-code-foreground, var(--jp-content-font-color1, white)));\n",
       "    --sklearn-color-icon: #878787;\n",
       "  }\n",
       "}\n",
       "\n",
       "#sk-container-id-1 {\n",
       "  color: var(--sklearn-color-text);\n",
       "}\n",
       "\n",
       "#sk-container-id-1 pre {\n",
       "  padding: 0;\n",
       "}\n",
       "\n",
       "#sk-container-id-1 input.sk-hidden--visually {\n",
       "  border: 0;\n",
       "  clip: rect(1px 1px 1px 1px);\n",
       "  clip: rect(1px, 1px, 1px, 1px);\n",
       "  height: 1px;\n",
       "  margin: -1px;\n",
       "  overflow: hidden;\n",
       "  padding: 0;\n",
       "  position: absolute;\n",
       "  width: 1px;\n",
       "}\n",
       "\n",
       "#sk-container-id-1 div.sk-dashed-wrapped {\n",
       "  border: 1px dashed var(--sklearn-color-line);\n",
       "  margin: 0 0.4em 0.5em 0.4em;\n",
       "  box-sizing: border-box;\n",
       "  padding-bottom: 0.4em;\n",
       "  background-color: var(--sklearn-color-background);\n",
       "}\n",
       "\n",
       "#sk-container-id-1 div.sk-container {\n",
       "  /* jupyter's `normalize.less` sets `[hidden] { display: none; }`\n",
       "     but bootstrap.min.css set `[hidden] { display: none !important; }`\n",
       "     so we also need the `!important` here to be able to override the\n",
       "     default hidden behavior on the sphinx rendered scikit-learn.org.\n",
       "     See: https://github.com/scikit-learn/scikit-learn/issues/21755 */\n",
       "  display: inline-block !important;\n",
       "  position: relative;\n",
       "}\n",
       "\n",
       "#sk-container-id-1 div.sk-text-repr-fallback {\n",
       "  display: none;\n",
       "}\n",
       "\n",
       "div.sk-parallel-item,\n",
       "div.sk-serial,\n",
       "div.sk-item {\n",
       "  /* draw centered vertical line to link estimators */\n",
       "  background-image: linear-gradient(var(--sklearn-color-text-on-default-background), var(--sklearn-color-text-on-default-background));\n",
       "  background-size: 2px 100%;\n",
       "  background-repeat: no-repeat;\n",
       "  background-position: center center;\n",
       "}\n",
       "\n",
       "/* Parallel-specific style estimator block */\n",
       "\n",
       "#sk-container-id-1 div.sk-parallel-item::after {\n",
       "  content: \"\";\n",
       "  width: 100%;\n",
       "  border-bottom: 2px solid var(--sklearn-color-text-on-default-background);\n",
       "  flex-grow: 1;\n",
       "}\n",
       "\n",
       "#sk-container-id-1 div.sk-parallel {\n",
       "  display: flex;\n",
       "  align-items: stretch;\n",
       "  justify-content: center;\n",
       "  background-color: var(--sklearn-color-background);\n",
       "  position: relative;\n",
       "}\n",
       "\n",
       "#sk-container-id-1 div.sk-parallel-item {\n",
       "  display: flex;\n",
       "  flex-direction: column;\n",
       "}\n",
       "\n",
       "#sk-container-id-1 div.sk-parallel-item:first-child::after {\n",
       "  align-self: flex-end;\n",
       "  width: 50%;\n",
       "}\n",
       "\n",
       "#sk-container-id-1 div.sk-parallel-item:last-child::after {\n",
       "  align-self: flex-start;\n",
       "  width: 50%;\n",
       "}\n",
       "\n",
       "#sk-container-id-1 div.sk-parallel-item:only-child::after {\n",
       "  width: 0;\n",
       "}\n",
       "\n",
       "/* Serial-specific style estimator block */\n",
       "\n",
       "#sk-container-id-1 div.sk-serial {\n",
       "  display: flex;\n",
       "  flex-direction: column;\n",
       "  align-items: center;\n",
       "  background-color: var(--sklearn-color-background);\n",
       "  padding-right: 1em;\n",
       "  padding-left: 1em;\n",
       "}\n",
       "\n",
       "\n",
       "/* Toggleable style: style used for estimator/Pipeline/ColumnTransformer box that is\n",
       "clickable and can be expanded/collapsed.\n",
       "- Pipeline and ColumnTransformer use this feature and define the default style\n",
       "- Estimators will overwrite some part of the style using the `sk-estimator` class\n",
       "*/\n",
       "\n",
       "/* Pipeline and ColumnTransformer style (default) */\n",
       "\n",
       "#sk-container-id-1 div.sk-toggleable {\n",
       "  /* Default theme specific background. It is overwritten whether we have a\n",
       "  specific estimator or a Pipeline/ColumnTransformer */\n",
       "  background-color: var(--sklearn-color-background);\n",
       "}\n",
       "\n",
       "/* Toggleable label */\n",
       "#sk-container-id-1 label.sk-toggleable__label {\n",
       "  cursor: pointer;\n",
       "  display: flex;\n",
       "  width: 100%;\n",
       "  margin-bottom: 0;\n",
       "  padding: 0.5em;\n",
       "  box-sizing: border-box;\n",
       "  text-align: center;\n",
       "  align-items: start;\n",
       "  justify-content: space-between;\n",
       "  gap: 0.5em;\n",
       "}\n",
       "\n",
       "#sk-container-id-1 label.sk-toggleable__label .caption {\n",
       "  font-size: 0.6rem;\n",
       "  font-weight: lighter;\n",
       "  color: var(--sklearn-color-text-muted);\n",
       "}\n",
       "\n",
       "#sk-container-id-1 label.sk-toggleable__label-arrow:before {\n",
       "  /* Arrow on the left of the label */\n",
       "  content: \"▸\";\n",
       "  float: left;\n",
       "  margin-right: 0.25em;\n",
       "  color: var(--sklearn-color-icon);\n",
       "}\n",
       "\n",
       "#sk-container-id-1 label.sk-toggleable__label-arrow:hover:before {\n",
       "  color: var(--sklearn-color-text);\n",
       "}\n",
       "\n",
       "/* Toggleable content - dropdown */\n",
       "\n",
       "#sk-container-id-1 div.sk-toggleable__content {\n",
       "  max-height: 0;\n",
       "  max-width: 0;\n",
       "  overflow: hidden;\n",
       "  text-align: left;\n",
       "  /* unfitted */\n",
       "  background-color: var(--sklearn-color-unfitted-level-0);\n",
       "}\n",
       "\n",
       "#sk-container-id-1 div.sk-toggleable__content.fitted {\n",
       "  /* fitted */\n",
       "  background-color: var(--sklearn-color-fitted-level-0);\n",
       "}\n",
       "\n",
       "#sk-container-id-1 div.sk-toggleable__content pre {\n",
       "  margin: 0.2em;\n",
       "  border-radius: 0.25em;\n",
       "  color: var(--sklearn-color-text);\n",
       "  /* unfitted */\n",
       "  background-color: var(--sklearn-color-unfitted-level-0);\n",
       "}\n",
       "\n",
       "#sk-container-id-1 div.sk-toggleable__content.fitted pre {\n",
       "  /* unfitted */\n",
       "  background-color: var(--sklearn-color-fitted-level-0);\n",
       "}\n",
       "\n",
       "#sk-container-id-1 input.sk-toggleable__control:checked~div.sk-toggleable__content {\n",
       "  /* Expand drop-down */\n",
       "  max-height: 200px;\n",
       "  max-width: 100%;\n",
       "  overflow: auto;\n",
       "}\n",
       "\n",
       "#sk-container-id-1 input.sk-toggleable__control:checked~label.sk-toggleable__label-arrow:before {\n",
       "  content: \"▾\";\n",
       "}\n",
       "\n",
       "/* Pipeline/ColumnTransformer-specific style */\n",
       "\n",
       "#sk-container-id-1 div.sk-label input.sk-toggleable__control:checked~label.sk-toggleable__label {\n",
       "  color: var(--sklearn-color-text);\n",
       "  background-color: var(--sklearn-color-unfitted-level-2);\n",
       "}\n",
       "\n",
       "#sk-container-id-1 div.sk-label.fitted input.sk-toggleable__control:checked~label.sk-toggleable__label {\n",
       "  background-color: var(--sklearn-color-fitted-level-2);\n",
       "}\n",
       "\n",
       "/* Estimator-specific style */\n",
       "\n",
       "/* Colorize estimator box */\n",
       "#sk-container-id-1 div.sk-estimator input.sk-toggleable__control:checked~label.sk-toggleable__label {\n",
       "  /* unfitted */\n",
       "  background-color: var(--sklearn-color-unfitted-level-2);\n",
       "}\n",
       "\n",
       "#sk-container-id-1 div.sk-estimator.fitted input.sk-toggleable__control:checked~label.sk-toggleable__label {\n",
       "  /* fitted */\n",
       "  background-color: var(--sklearn-color-fitted-level-2);\n",
       "}\n",
       "\n",
       "#sk-container-id-1 div.sk-label label.sk-toggleable__label,\n",
       "#sk-container-id-1 div.sk-label label {\n",
       "  /* The background is the default theme color */\n",
       "  color: var(--sklearn-color-text-on-default-background);\n",
       "}\n",
       "\n",
       "/* On hover, darken the color of the background */\n",
       "#sk-container-id-1 div.sk-label:hover label.sk-toggleable__label {\n",
       "  color: var(--sklearn-color-text);\n",
       "  background-color: var(--sklearn-color-unfitted-level-2);\n",
       "}\n",
       "\n",
       "/* Label box, darken color on hover, fitted */\n",
       "#sk-container-id-1 div.sk-label.fitted:hover label.sk-toggleable__label.fitted {\n",
       "  color: var(--sklearn-color-text);\n",
       "  background-color: var(--sklearn-color-fitted-level-2);\n",
       "}\n",
       "\n",
       "/* Estimator label */\n",
       "\n",
       "#sk-container-id-1 div.sk-label label {\n",
       "  font-family: monospace;\n",
       "  font-weight: bold;\n",
       "  display: inline-block;\n",
       "  line-height: 1.2em;\n",
       "}\n",
       "\n",
       "#sk-container-id-1 div.sk-label-container {\n",
       "  text-align: center;\n",
       "}\n",
       "\n",
       "/* Estimator-specific */\n",
       "#sk-container-id-1 div.sk-estimator {\n",
       "  font-family: monospace;\n",
       "  border: 1px dotted var(--sklearn-color-border-box);\n",
       "  border-radius: 0.25em;\n",
       "  box-sizing: border-box;\n",
       "  margin-bottom: 0.5em;\n",
       "  /* unfitted */\n",
       "  background-color: var(--sklearn-color-unfitted-level-0);\n",
       "}\n",
       "\n",
       "#sk-container-id-1 div.sk-estimator.fitted {\n",
       "  /* fitted */\n",
       "  background-color: var(--sklearn-color-fitted-level-0);\n",
       "}\n",
       "\n",
       "/* on hover */\n",
       "#sk-container-id-1 div.sk-estimator:hover {\n",
       "  /* unfitted */\n",
       "  background-color: var(--sklearn-color-unfitted-level-2);\n",
       "}\n",
       "\n",
       "#sk-container-id-1 div.sk-estimator.fitted:hover {\n",
       "  /* fitted */\n",
       "  background-color: var(--sklearn-color-fitted-level-2);\n",
       "}\n",
       "\n",
       "/* Specification for estimator info (e.g. \"i\" and \"?\") */\n",
       "\n",
       "/* Common style for \"i\" and \"?\" */\n",
       "\n",
       ".sk-estimator-doc-link,\n",
       "a:link.sk-estimator-doc-link,\n",
       "a:visited.sk-estimator-doc-link {\n",
       "  float: right;\n",
       "  font-size: smaller;\n",
       "  line-height: 1em;\n",
       "  font-family: monospace;\n",
       "  background-color: var(--sklearn-color-background);\n",
       "  border-radius: 1em;\n",
       "  height: 1em;\n",
       "  width: 1em;\n",
       "  text-decoration: none !important;\n",
       "  margin-left: 0.5em;\n",
       "  text-align: center;\n",
       "  /* unfitted */\n",
       "  border: var(--sklearn-color-unfitted-level-1) 1pt solid;\n",
       "  color: var(--sklearn-color-unfitted-level-1);\n",
       "}\n",
       "\n",
       ".sk-estimator-doc-link.fitted,\n",
       "a:link.sk-estimator-doc-link.fitted,\n",
       "a:visited.sk-estimator-doc-link.fitted {\n",
       "  /* fitted */\n",
       "  border: var(--sklearn-color-fitted-level-1) 1pt solid;\n",
       "  color: var(--sklearn-color-fitted-level-1);\n",
       "}\n",
       "\n",
       "/* On hover */\n",
       "div.sk-estimator:hover .sk-estimator-doc-link:hover,\n",
       ".sk-estimator-doc-link:hover,\n",
       "div.sk-label-container:hover .sk-estimator-doc-link:hover,\n",
       ".sk-estimator-doc-link:hover {\n",
       "  /* unfitted */\n",
       "  background-color: var(--sklearn-color-unfitted-level-3);\n",
       "  color: var(--sklearn-color-background);\n",
       "  text-decoration: none;\n",
       "}\n",
       "\n",
       "div.sk-estimator.fitted:hover .sk-estimator-doc-link.fitted:hover,\n",
       ".sk-estimator-doc-link.fitted:hover,\n",
       "div.sk-label-container:hover .sk-estimator-doc-link.fitted:hover,\n",
       ".sk-estimator-doc-link.fitted:hover {\n",
       "  /* fitted */\n",
       "  background-color: var(--sklearn-color-fitted-level-3);\n",
       "  color: var(--sklearn-color-background);\n",
       "  text-decoration: none;\n",
       "}\n",
       "\n",
       "/* Span, style for the box shown on hovering the info icon */\n",
       ".sk-estimator-doc-link span {\n",
       "  display: none;\n",
       "  z-index: 9999;\n",
       "  position: relative;\n",
       "  font-weight: normal;\n",
       "  right: .2ex;\n",
       "  padding: .5ex;\n",
       "  margin: .5ex;\n",
       "  width: min-content;\n",
       "  min-width: 20ex;\n",
       "  max-width: 50ex;\n",
       "  color: var(--sklearn-color-text);\n",
       "  box-shadow: 2pt 2pt 4pt #999;\n",
       "  /* unfitted */\n",
       "  background: var(--sklearn-color-unfitted-level-0);\n",
       "  border: .5pt solid var(--sklearn-color-unfitted-level-3);\n",
       "}\n",
       "\n",
       ".sk-estimator-doc-link.fitted span {\n",
       "  /* fitted */\n",
       "  background: var(--sklearn-color-fitted-level-0);\n",
       "  border: var(--sklearn-color-fitted-level-3);\n",
       "}\n",
       "\n",
       ".sk-estimator-doc-link:hover span {\n",
       "  display: block;\n",
       "}\n",
       "\n",
       "/* \"?\"-specific style due to the `<a>` HTML tag */\n",
       "\n",
       "#sk-container-id-1 a.estimator_doc_link {\n",
       "  float: right;\n",
       "  font-size: 1rem;\n",
       "  line-height: 1em;\n",
       "  font-family: monospace;\n",
       "  background-color: var(--sklearn-color-background);\n",
       "  border-radius: 1rem;\n",
       "  height: 1rem;\n",
       "  width: 1rem;\n",
       "  text-decoration: none;\n",
       "  /* unfitted */\n",
       "  color: var(--sklearn-color-unfitted-level-1);\n",
       "  border: var(--sklearn-color-unfitted-level-1) 1pt solid;\n",
       "}\n",
       "\n",
       "#sk-container-id-1 a.estimator_doc_link.fitted {\n",
       "  /* fitted */\n",
       "  border: var(--sklearn-color-fitted-level-1) 1pt solid;\n",
       "  color: var(--sklearn-color-fitted-level-1);\n",
       "}\n",
       "\n",
       "/* On hover */\n",
       "#sk-container-id-1 a.estimator_doc_link:hover {\n",
       "  /* unfitted */\n",
       "  background-color: var(--sklearn-color-unfitted-level-3);\n",
       "  color: var(--sklearn-color-background);\n",
       "  text-decoration: none;\n",
       "}\n",
       "\n",
       "#sk-container-id-1 a.estimator_doc_link.fitted:hover {\n",
       "  /* fitted */\n",
       "  background-color: var(--sklearn-color-fitted-level-3);\n",
       "}\n",
       "</style><div id=\"sk-container-id-1\" class=\"sk-top-container\"><div class=\"sk-text-repr-fallback\"><pre>KNeighborsClassifier(n_neighbors=1)</pre><b>In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook. <br />On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.</b></div><div class=\"sk-container\" hidden><div class=\"sk-item\"><div class=\"sk-estimator fitted sk-toggleable\"><input class=\"sk-toggleable__control sk-hidden--visually\" id=\"sk-estimator-id-1\" type=\"checkbox\" checked><label for=\"sk-estimator-id-1\" class=\"sk-toggleable__label fitted sk-toggleable__label-arrow\"><div><div>KNeighborsClassifier</div></div><div><a class=\"sk-estimator-doc-link fitted\" rel=\"noreferrer\" target=\"_blank\" href=\"https://scikit-learn.org/1.6/modules/generated/sklearn.neighbors.KNeighborsClassifier.html\">?<span>Documentation for KNeighborsClassifier</span></a><span class=\"sk-estimator-doc-link fitted\">i<span>Fitted</span></span></div></label><div class=\"sk-toggleable__content fitted\"><pre>KNeighborsClassifier(n_neighbors=1)</pre></div> </div></div></div></div>"
      ],
      "text/plain": [
       "KNeighborsClassifier(n_neighbors=1)"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "knn.fit(X, y)"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 4. 用模型推理(预测)用户的喜好"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "new_user = np.array([[3, 4]])\n",
    "prediction = knn.predict(new_user)"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 5. 数据可视化"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "findfont: Generic family 'sans-serif' not found because none of the following families were found: Noto Sans CJK SC\n",
      "findfont: Generic family 'sans-serif' not found because none of the following families were found: Noto Sans CJK SC\n",
      "findfont: Generic family 'sans-serif' not found because none of the following families were found: Noto Sans CJK SC\n",
      "findfont: Generic family 'sans-serif' not found because none of the following families were found: Noto Sans CJK SC\n",
      "findfont: Generic family 'sans-serif' not found because none of the following families were found: Noto Sans CJK SC\n",
      "findfont: Generic family 'sans-serif' not found because none of the following families were found: Noto Sans CJK SC\n",
      "findfont: Generic family 'sans-serif' not found because none of the following families were found: Noto Sans CJK SC\n",
      "findfont: Generic family 'sans-serif' not found because none of the following families were found: Noto Sans CJK SC\n",
      "findfont: Generic family 'sans-serif' not found because none of the following families were found: Noto Sans CJK SC\n",
      "findfont: Generic family 'sans-serif' not found because none of the following families were found: Noto Sans CJK SC\n",
      "findfont: Generic family 'sans-serif' not found because none of the following families were found: Noto Sans CJK SC\n",
      "findfont: Generic family 'sans-serif' not found because none of the following families were found: Noto Sans CJK SC\n",
      "findfont: Generic family 'sans-serif' not found because none of the following families were found: Noto Sans CJK SC\n",
      "findfont: Generic family 'sans-serif' not found because none of the following families were found: Noto Sans CJK SC\n",
      "findfont: Generic family 'sans-serif' not found because none of the following families were found: Noto Sans CJK SC\n",
      "findfont: Generic family 'sans-serif' not found because none of the following families were found: Noto Sans CJK SC\n",
      "findfont: Generic family 'sans-serif' not found because none of the following families were found: Noto Sans CJK SC\n",
      "findfont: Generic family 'sans-serif' not found because none of the following families were found: Noto Sans CJK SC\n",
      "findfont: Generic family 'sans-serif' not found because none of the following families were found: Noto Sans CJK SC\n",
      "findfont: Generic family 'sans-serif' not found because none of the following families were found: Noto Sans CJK SC\n",
      "findfont: Generic family 'sans-serif' not found because none of the following families were found: Noto Sans CJK SC\n",
      "findfont: Generic family 'sans-serif' not found because none of the following families were found: Noto Sans CJK SC\n",
      "findfont: Generic family 'sans-serif' not found because none of the following families were found: Noto Sans CJK SC\n",
      "findfont: Generic family 'sans-serif' not found because none of the following families were found: Noto Sans CJK SC\n",
      "findfont: Generic family 'sans-serif' not found because none of the following families were found: Noto Sans CJK SC\n",
      "findfont: Generic family 'sans-serif' not found because none of the following families were found: Noto Sans CJK SC\n",
      "findfont: Generic family 'sans-serif' not found because none of the following families were found: Noto Sans CJK SC\n",
      "findfont: Generic family 'sans-serif' not found because none of the following families were found: Noto Sans CJK SC\n",
      "findfont: Generic family 'sans-serif' not found because none of the following families were found: Noto Sans CJK SC\n",
      "findfont: Generic family 'sans-serif' not found because none of the following families were found: Noto Sans CJK SC\n",
      "findfont: Generic family 'sans-serif' not found because none of the following families were found: Noto Sans CJK SC\n",
      "findfont: Generic family 'sans-serif' not found because none of the following families were found: Noto Sans CJK SC\n",
      "findfont: Generic family 'sans-serif' not found because none of the following families were found: Noto Sans CJK SC\n",
      "findfont: Generic family 'sans-serif' not found because none of the following families were found: Noto Sans CJK SC\n",
      "findfont: Generic family 'sans-serif' not found because none of the following families were found: Noto Sans CJK SC\n",
      "findfont: Generic family 'sans-serif' not found because none of the following families were found: Noto Sans CJK SC\n",
      "findfont: Generic family 'sans-serif' not found because none of the following families were found: Noto Sans CJK SC\n",
      "findfont: Generic family 'sans-serif' not found because none of the following families were found: Noto Sans CJK SC\n",
      "findfont: Generic family 'sans-serif' not found because none of the following families were found: Noto Sans CJK SC\n",
      "findfont: Generic family 'sans-serif' not found because none of the following families were found: Noto Sans CJK SC\n",
      "findfont: Generic family 'sans-serif' not found because none of the following families were found: Noto Sans CJK SC\n",
      "findfont: Generic family 'sans-serif' not found because none of the following families were found: Noto Sans CJK SC\n",
      "findfont: Generic family 'sans-serif' not found because none of the following families were found: Noto Sans CJK SC\n",
      "findfont: Generic family 'sans-serif' not found because none of the following families were found: Noto Sans CJK SC\n",
      "findfont: Generic family 'sans-serif' not found because none of the following families were found: Noto Sans CJK SC\n",
      "findfont: Generic family 'sans-serif' not found because none of the following families were found: Noto Sans CJK SC\n",
      "findfont: Generic family 'sans-serif' not found because none of the following families were found: Noto Sans CJK SC\n",
      "findfont: Generic family 'sans-serif' not found because none of the following families were found: Noto Sans CJK SC\n",
      "findfont: Generic family 'sans-serif' not found because none of the following families were found: Noto Sans CJK SC\n",
      "findfont: Generic family 'sans-serif' not found because none of the following families were found: Noto Sans CJK SC\n",
      "findfont: Generic family 'sans-serif' not found because none of the following families were found: Noto Sans CJK SC\n",
      "findfont: Generic family 'sans-serif' not found because none of the following families were found: Noto Sans CJK SC\n",
      "findfont: Generic family 'sans-serif' not found because none of the following families were found: Noto Sans CJK SC\n",
      "findfont: Generic family 'sans-serif' not found because none of the following families were found: Noto Sans CJK SC\n",
      "findfont: Generic family 'sans-serif' not found because none of the following families were found: Noto Sans CJK SC\n",
      "findfont: Generic family 'sans-serif' not found because none of the following families were found: Noto Sans CJK SC\n",
      "findfont: Generic family 'sans-serif' not found because none of the following families were found: Noto Sans CJK SC\n",
      "findfont: Generic family 'sans-serif' not found because none of the following families were found: Noto Sans CJK SC\n",
      "findfont: Generic family 'sans-serif' not found because none of the following families were found: Noto Sans CJK SC\n",
      "findfont: Generic family 'sans-serif' not found because none of the following families were found: Noto Sans CJK SC\n",
      "findfont: Generic family 'sans-serif' not found because none of the following families were found: Noto Sans CJK SC\n",
      "findfont: Generic family 'sans-serif' not found because none of the following families were found: Noto Sans CJK SC\n",
      "findfont: Generic family 'sans-serif' not found because none of the following families were found: Noto Sans CJK SC\n",
      "findfont: Generic family 'sans-serif' not found because none of the following families were found: Noto Sans CJK SC\n",
      "findfont: Generic family 'sans-serif' not found because none of the following families were found: Noto Sans CJK SC\n",
      "findfont: Generic family 'sans-serif' not found because none of the following families were found: Noto Sans CJK SC\n",
      "findfont: Generic family 'sans-serif' not found because none of the following families were found: Noto Sans CJK SC\n",
      "findfont: Generic family 'sans-serif' not found because none of the following families were found: Noto Sans CJK SC\n"
     ]
    },
    {
     "data": {
      "image/png": "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mz///JNNmzbl28/Pz4/333+fuLg4S9ucOXOYMmUKp0+fztN/8uTJTJkyJU97fHw8QUFBjgleREREnCojI4P+/fuTmppKaGioU/ZRas4U5b6puKCCqCgmTpxodWYpLS2NiIgIunbt6vAvNSsri4SEBGJiYvD19XXo2KWBp+cHnp+jp+U3Z85fE3PBfHZh4cIEhgyJ4dKlv/KbPt0zzjKAjqG787TjZ4uzcsy90uNMpaIoyn1T8YYNG2y+qfha4eHhec4InT59mvDwcJv9/f398ff3z9Pu6+vrtB9IZ45dGnh6fuD5OXpKfo8/DmPG5J2ge+mSr+UfVG9vcz8PSNeKjqF785TjVxBH51gS35dLJ1obhsGIESNYvnw53377bb5vKr5WdHQ069ats2pLSEggOjraWWGKSCnl5wfXTTHMY/Ro6zkrUrroGEpp4tIzRcOHDyc+Pp7PP//c8qZigLJly1reNzNw4ECqVavG9OnTARg5ciSdOnVi5syZ9OrVi6VLl7J9+3beffddl+UhIq7z6qvmP6+/g8nb2/yPae56Kb10DKW0cOmZosK8qTg5OZmUlBTLcocOHYiPj+fdd9+lefPmfPLJJ6xYsYImTZq4IgURKQVefRUyMszzTsD8Z0aG/jF1JzqGUhq49ExRYW58S0xMzNPWt29f+vbt64SIRMRd+fmZJ+KuWmX+08Ona3gkHUNxNb37TERERAQVRSIiIiKAiiIRERERQEWRiIiICKCiSERERARQUSQiIiICqCgSERERAVQUiYiIiAAqikREREQAFUUiIiIigIoiEREREUBFkYiIiAigokhEREQEUFEkIiIiAqgoEhEREQFUFImIiIgAKopEREREABVFIiIiIoCKIhERERFARZGIiIgIoKJIREREBFBRJCIiIgKoKBIREREBVBSJiIiIACqKRERERAAVRSIiIiKAiiIRERERQEWRiIiICKCiSERERARQUSQiIiICqCgSERERAVxcFG3YsIG7776bqlWrYjKZWLFiRYH9ExMTMZlMeT6nTp0qmYBFRETEY7m0KLp48SLNmzfn7bfftmu7/fv3k5KSYvmEhYU5KUIRERG5Wfi4cuc9evSgR48edm8XFhZGuXLlHB+QiIiI3LRcWhQVVYsWLcjMzKRJkyZMnjyZjh075ts3MzOTzMxMy3JaWhoAWVlZZGVlOTSu3PEc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bbWNOx3HouR3vdJ+DK9Xrlw56tevn2+87nT8QHefOU10dDTr1q2zaktISChwboAnSEpKokqVKq4OwybDMBgxYgTLly/n22+/pXbt2jfcxp2OY1Hyu152dja7d+8utcfwejk5OWRmZtpc507HriAF5Xi90n78unTpwu7du0lKSrJ8WrduzYABA0hKSrJZMLjTcSxKftcr7cfweunp6Rw6dCjfeN3p+AG6+6ywLly4YOzatcvYtWuXARivv/66sWvXLuPo0aOGYRjGhAkTjIceesjS//fffzeCgoKMcePGGfv27TPefvttw9vb2/j6669dlcIN2ZvjrFmzjBUrVhgHDhwwdu/ebYwcOdLw8vIy1q5d66oUCvT4448bZcuWNRITE42UlBTLJyMjw9LnoYceMiZMmGBZ3rx5s+Hj42O89tprxr59+4znn3/e8PX1NXbv3u2KFApUlPymTJlirFmzxjh06JCxY8cO4//+7/+MgIAAY+/eva5IoUATJkww1q9fbxw+fNj4+eefjQkTJhgmk8n45ptvDMNw72OXy94c3en45ef6u7M84The60b5udsxHDNmjJGYmGgcPnzY2Lx5s3HXXXcZlSpVMs6cOWMYhvsfPxVFhZR7+/n1n0GDBhmGYRiDBg0yOnXqlGebFi1aGH5+fsatt95qLFq0qMTjtoe9Ob7yyitGnTp1jICAAKNChQpG586djW+//dY1wReCrdwAq+PSqVMnS765Pv74Y6N+/fqGn5+f0bhxY+Orr74q2cALqSj5jRo1yqhRo4bh5+dnVK5c2ejZs6exc+fOkg++EIYMGWLUrFnT8PPzM2655RajS5culmLBMNz72OWyN0d3On75ub5o8ITjeK0b5edux7Bfv35GlSpVDD8/P6NatWpGv379jIMHD1rWu/vxMxmGYZTceSkRERGR0klzikRERERQUSQiIiICqCgSERERAVQUiYiIiAAqikREREQAFUUiIiIigIoiEREREUBFkYi4mMlkYsWKFa4Oo9gmT55MixYtXB2GiBSDiiIRsRg8eDAmk4nHHnssz7rhw4djMpkYPHiwQ/eZkpJi9ebt4ujWrRve3t5s27bNIePlx1YhN3bs2DzveBIR96KiSESsREREsHTpUi5dumRpu3z5MvHx8dSoUcPh+wsPD8ff37/Y4yQnJ7NlyxZGjBjBwoUL7d4+Ozub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",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.title(\"User Movie Preference\", size=15) \n",
    "plt.xlabel(\"Movie A rating\")\n",
    "plt.ylabel(\"Movie B rating\")\n",
    "plt.grid()\n",
    "\n",
    "# 绘制原始样本点，要求不同的影片喜好类别用不同的颜色标记\n",
    "plt.scatter(X[y==0, 0], X[y==0, 1], c='blue', label='Action')\n",
    "plt.scatter(X[y==1, 0], X[y==1, 1], c='orange', label='Comedy')\n",
    "\n",
    "# 绘制新数据点，用红色x标记，大小为8\n",
    "plt.scatter(X[y==0, 0], X[y==0, 1], c='blue', label='Action')\n",
    "plt.scatter(X[y==1, 0], X[y==1, 1], c='orange', label='Comedy')\n",
    "\n",
    "# 新数据最近邻索引为第一个最近邻的索引\n",
    "dist, idx =  knn.kneighbors(new_user)\n",
    "nearest =idx[0][0] # 获取最近邻点的坐标，这是一个列表，第一个元素是x坐标，第二个元素是y坐标\n",
    "\n",
    "# 用红线标记新数据点与最近邻点的连接线\n",
    "plt.plot([new_user[0, 0], X[idx[0][0], 0]], [new_user[0, 1], X[idx[0][0], 1]], 'r--')\n",
    "\n",
    "# 为每个点添加坐标文本  \n",
    "for x, y in zip(X[:, 0], X[:, 1]):\n",
    "    plt.text(x, y+0.1, f'({x}, {y})') \n",
    "\n",
    "# 为新数据点添加坐标文本\n",
    "plt.text(new_user[0,0], new_user[0,1]+0.1, f'({new_user[0,0]}, {new_user[0,1]})')\n",
    "plt.show()"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.9"
  },
  "orig_nbformat": 4
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
